#ifndef  CONNECTIONCONFIGURATION_H
#define  CONNECTIONCONFIGURATION_H

#include <string>


class ConnectionConfiguration {
public:
    /**
     * Creates a new ConnectionConfiguration for the specified service name.
     * A DNS SRV lookup will be performed to find out the actual host address
     * and port to use for the connection.
     *
     * @param serviceName the name of the service provided by an XMPP server.
     */
	ConnectionConfiguration(std::string & serviceName);

    /**
     * Creates a new ConnectionConfiguration using the specified host, port and
     * service name. This is useful for manually overriding the DNS SRV lookup
     * process that's used with the {@link #ConnectionConfiguration(String)}
     * constructor. For example, say that an XMPP server is running at localhost
     * in an internal network on port 5222 but is configured to think that it's
     * "example.com" for testing purposes. This constructor is necessary to connect
     * to the server in that case since a DNS SRV lookup for example.com would not
     * point to the local testing server.
     *
     * @param host the host where the XMPP server is running.
     * @param port the port where the XMPP is listening.
     * @param serviceName the name of the service provided by an XMPP server.
     */
	ConnectionConfiguration(std::string & host, int port, std::string & serviceName);

    /**
     * Creates a new ConnectionConfiguration for a connection that will connect
     * to the desired host and port.
     *
     * @param host the host where the XMPP server is running.
     * @param port the port where the XMPP is listening.
     */
	ConnectionConfiguration(std::string & host, int port);

	ConnectionConfiguration(const ConnectionConfiguration & cc);

    /**
     * Returns the server name of the target server.
     *
     * @return the server name of the target server.
     */
	std::string getServiceName() { return serviceName;}

    /**
     * Returns the host to use when establishing the connection. The host and port to use
     * might have been resolved by a DNS lookup as specified by the XMPP spec (and therefore
     * may not match the {@link #getServiceName service name}.
     *
     * @return the host to use when establishing the connection.
     */
	std::string getHost() { return host; }

    /**
     * Returns the port to use when establishing the connection. The host and port to use
     * might have been resolved by a DNS lookup as specified by the XMPP spec.
     *
     * @return the port to use when establishing the connection.
     */
    int getPort() { return port; }

	typedef enum {

        /**
         * Securirty via TLS encryption is required in order to connect. If the server
         * does not offer TLS or if the TLS negotiaton fails, the connection to the server
         * will fail.
         */
        REQUIRED ,

        /**
         * Security via TLS encryption is used whenever it's available. This is the
         * default setting.
         */
        ENABLED ,

        /**
         * Security via TLS encryption is disabled and only un-encrypted connections will
         * be used. If only TLS encryption is available from the server, the connection
         * will fail.
         */
        DISABLED
    } SecurityMode;

    /**
     * Returns the TLS security mode used when making the connection. By default,
     * the mode is {@link SecurityMode#enabled}.
     *
     * @return the security mode.
     */
    SecurityMode getSecurityMode() { return securityMode; }

    /**
     * Sets the TLS security mode used when making the connection. By default,
     * the mode is {@link SecurityMode#enabled}.
     *
     * @param securityMode the security mode.
     */
    void setSecurityMode(SecurityMode securityMode) { this->securityMode = securityMode; }

    /**
     * Retuns the path to the trust store file. The trust store file contains the root
     * certificates of several well known CAs. By default, will attempt to use the
     * the file located in $JREHOME/lib/security/cacerts.
     *
     * @return the path to the truststore file.
     */
	std::string getTruststorePath() { return truststorePath; }

    /**
     * Sets the path to the trust store file. The truststore file contains the root
     * certificates of several well?known CAs. By default Smack is going to use
     * the file located in $JREHOME/lib/security/cacerts.
     *
     * @param truststorePath the path to the truststore file.
     */
    void setTruststorePath(std::string & truststorePath) { this->truststorePath = truststorePath; }

    /**
     * Returns the trust store type, or <tt>null</tt> if it's not set.
     *
     * @return the trust store type.
     */
	std::string getTruststoreType() { return truststoreType; }

    /**
     * Sets the trust store type.
     *
     * @param truststoreType the trust store type.
     */
    void setTruststoreType(std::string & truststoreType) { this->truststoreType = truststoreType; }

    /**
     * Returns the password to use to access the trust store file. It is assumed that all
     * certificates share the same password in the trust store.
     *
     * @return the password to use to access the truststore file.
     */
	std::string getTruststorePassword() { return truststorePassword; }
	
    /**
     * Sets the password to use to access the trust store file. It is assumed that all
     * certificates share the same password in the trust store.
     *
     * @param truststorePassword the password to use to access the truststore file.
     */
    void setTruststorePassword(std::string & truststorePassword) { this->truststorePassword = truststorePassword; }

    /**
     * Returns true if the whole chain of certificates presented by the server are going to
     * be checked. By default the certificate chain is not verified.
     *
     * @return true if the whole chaing of certificates presented by the server are going to
     *         be checked.
     */
    bool isVerifyChainEnabled() { return verifyChainEnabled; }

    /**
     * Sets if the whole chain of certificates presented by the server are going to
     * be checked. By default the certificate chain is not verified.
     *
     * @param verifyChainEnabled if the whole chaing of certificates presented by the server
     *        are going to be checked.
     */
    void setVerifyChainEnabled(bool verifyChainEnabled) { this->verifyChainEnabled = verifyChainEnabled; }

    /**
     * Returns true if root CA checking is going to be done. By default checking is disabled.
     *
     * @return true if root CA checking is going to be done.
     */
    bool isVerifyRootCAEnabled() { return verifyRootCAEnabled; }

    /**
     * Sets if root CA checking is going to be done. By default checking is disabled.
     *
     * @param verifyRootCAEnabled if root CA checking is going to be done.
     */
    void setVerifyRootCAEnabled(bool verifyRootCAEnabled) { this->verifyRootCAEnabled = verifyRootCAEnabled; }

    /**
     * Returns true if self-signed certificates are going to be accepted. By default
     * this option is disabled.
     *
     * @return true if self-signed certificates are going to be accepted.
     */
    bool isSelfSignedCertificateEnabled() { return selfSignedCertificateEnabled; }

    /**
     * Sets if self-signed certificates are going to be accepted. By default
     * this option is disabled.
     *
     * @param selfSignedCertificateEnabled if self-signed certificates are going to be accepted.
     */
    void setSelfSignedCertificateEnabled(bool selfSignedCertificateEnabled) { this->selfSignedCertificateEnabled = selfSignedCertificateEnabled; }

    /**
     * Returns true if certificates presented by the server are going to be checked for their
     * validity. By default certificates are not verified.
     *
     * @return true if certificates presented by the server are going to be checked for their
     *         validity.
     */
    bool isExpiredCertificatesCheckEnabled() { return expiredCertificatesCheckEnabled; }
	
    /**
     * Sets if certificates presented by the server are going to be checked for their
     * validity. By default certificates are not verified.
     *
     * @param expiredCertificatesCheckEnabled if certificates presented by the server are going
     *        to be checked for their validity.
     */
    void setExpiredCertificatesCheckEnabled(bool expiredCertificatesCheckEnabled) { this->expiredCertificatesCheckEnabled = expiredCertificatesCheckEnabled; }
	
    /**
     * Returns true if certificates presented by the server are going to be checked for their
     * domain. By default certificates are not verified.
     *
     * @return true if certificates presented by the server are going to be checked for their
     *         domain.
     */
    bool isNotMatchingDomainCheckEnabled() { return notMatchingDomainCheckEnabled; }
   
	/**
     * Sets if certificates presented by the server are going to be checked for their
     * domain. By default certificates are not verified.
     *
     * @param notMatchingDomainCheckEnabled if certificates presented by the server are going
     *        to be checked for their domain.
     */
    void setNotMatchingDomainCheckEnabled(bool notMatchingDomainCheckEnabled) { this->notMatchingDomainCheckEnabled = notMatchingDomainCheckEnabled; }

    /**
     * Returns true if the connection is going to use stream compression. Stream compression
     * will be requested after TLS was established (if TLS was enabled) and only if the server
     * offered stream compression. With stream compression network traffic can be reduced
     * up to 90%. By default compression is disabled.
     *
     * @return true if the connection is going to use stream compression.
     */
    bool isCompressionEnabled() { return compressionEnabled; }

    /**
     * Sets if the connection is going to use stream compression. Stream compression
     * will be requested after TLS was established (if TLS was enabled) and only if the server
     * offered stream compression. With stream compression network traffic can be reduced
     * up to 90%. By default compression is disabled.
     *
     * @param compressionEnabled if the connection is going to use stream compression.
     */
    void setCompressionEnabled(bool compressionEnabled) { this->compressionEnabled = compressionEnabled; }

    /**
     * Returns true if the client is going to use SASL authentication when logging into the
     * server. If SASL authenticatin fails then the client will try to use non-sasl authentication.
     * By default SASL is enabled.
     *
     * @return true if the client is going to use SASL authentication when logging into the
     *         server.
     */
    bool isSASLAuthenticationEnabled() { return saslAuthenticationEnabled; }

    /**
     * Sets whether the client will use SASL authentication when logging into the
     * server. If SASL authenticatin fails then the client will try to use non-sasl authentication.
     * By default, SASL is enabled.
     *
     * @param saslAuthenticationEnabled if the client is going to use SASL authentication when
     *        logging into the server.
     */
    void setSASLAuthenticationEnabled(bool saslAuthenticationEnabled) { this->saslAuthenticationEnabled = saslAuthenticationEnabled; }

    /**
     * Returns true if the new connection about to be establish is going to be debugged. By
     * default the value of {@link XMPPConnection#DEBUG_ENABLED} is used.
     *
     * @return true if the new connection about to be establish is going to be debugged.
     */
    bool isDebuggerEnabled() { return debuggerEnabled; }

    /**
     * Sets if the new connection about to be establish is going to be debugged. By
     * default the value of {@link XMPPConnection#DEBUG_ENABLED} is used.
     *
     * @param debuggerEnabled if the new connection about to be establish is going to be debugged.
     */
    void setDebuggerEnabled(bool debuggerEnabled) { this->debuggerEnabled = debuggerEnabled; }
    
    /**
     * Sets if the reconnection mechanism is allowed to be used. By default
     * reconnection is allowed.
     * 
     * @param isAllowed if the reconnection mechanism is allowed to use.
     */
    void setReconnectionAllowed(bool isAllowed) { this->reconnectionAllowed = isAllowed; }

    /**
     * Returns if the reconnection mechanism is allowed to be used. By default
     * reconnection is allowed.
     *
     * @return if the reconnection mechanism is allowed to be used.
     */
    bool isReconnectionAllowed() { return reconnectionAllowed; }
    

    /**
     * Returns the username to use when trying to reconnect to the server.
     *
     * @return the username to use when trying to reconnect to the server.
     */
	std::string getUsername() { return username; }
	
    /**
     * Returns the password to use when trying to reconnect to the server.
     *
     * @return the password to use when trying to reconnect to the server.
     */
	std::string getPassword() { return password; }

    /**
     * Returns the resource to use when trying to reconnect to the server.
     *
     * @return the resource to use when trying to reconnect to the server.
     */
	std::string getResource() { return resource; }

    /**
     * Returns true if an available presence should be sent when logging in while reconnecting.
     *
     * @return true if an available presence should be sent when logging in while reconnecting
     */
    bool isSendPresence() { return sendPresence; }

    void setLoginInfo(std::string & username, std::string & password, std::string & resource, bool sendPresence) ;

private:
	void init(std::string & host, int port, std::string & serviceName);


	std::string serviceName;

	std::string host;
	int port;

	std::string truststorePath;
	std::string truststoreType;
	std::string truststorePassword;
	bool verifyChainEnabled;
	bool verifyRootCAEnabled;
	bool selfSignedCertificateEnabled;
	bool expiredCertificatesCheckEnabled;
	bool notMatchingDomainCheckEnabled;

	bool compressionEnabled;

	bool saslAuthenticationEnabled;

	bool debuggerEnabled;

    // Flag that indicates if a reconnection should be attempted when abruptly disconnected
    bool reconnectionAllowed ;

	// Holds the authentication information for future reconnections
	std::string username;
	std::string password;
	std::string resource;
    bool sendPresence;
    SecurityMode securityMode;

};

#endif   /* ----- #ifndef CONNECTIONCONFIGURATION_INC  ----- */

